package com.example.vm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.constant.AuditStatus;
import com.common.constant.RedisConstant;
import com.common.domain.BasePage;
import com.common.domain.R;
import com.common.exception.CommonException;
import com.common.utils.IDUtils;
import com.example.api.client.UserClient;
import com.example.api.domain.entity.User;
import com.example.api.domain.vo.UserVO;
import com.example.vm.config.LocalCache;
import com.example.vm.domain.entity.Type;
import com.example.vm.domain.entity.Video;
import com.example.vm.domain.entity.VideoComment;
import com.example.vm.domain.entity.VideoLike;
import com.example.vm.domain.task.VideoTask;
import com.example.vm.domain.vo.HotVideo;
import com.example.vm.mapper.VideoMapper;
import com.example.vm.service.InterestPushService;
import com.example.vm.service.TypeService;
import com.example.vm.service.VideoLikeService;
import com.example.vm.service.VideoService;
import com.common.holder.UserHolder;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class VideoServiceImpl extends ServiceImpl<VideoMapper, Video> implements VideoService {

    @Autowired
    private UserClient userClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private InterestPushService interestPushService;
    @Autowired
    ObjectMapper objectMapper;
    @Autowired
    private TypeService typeService;
    @Autowired
    private IDUtils idUtils;
    @Autowired
    private VideoLikeService videoLikeService;
    @Override
    public IPage<Video> listVideo(BasePage basePage) {
        LambdaUpdateWrapper<Video> wrapper = new LambdaUpdateWrapper();
        System.out.println("UserIDDDDDD:"+UserHolder.getUserId());
        wrapper.eq(Video::getUserId, UserHolder.getUserId())
                .orderByDesc(Video::getCreatedTime);
        IPage page = page(basePage.page(),wrapper);
        setUserVoAndUrl(page.getRecords());
        return page;
    }

    @Override
    public List<Video> selectNDaysVideo(long id, int days, int limit) {
        LambdaQueryWrapper<Video> wrapper = new LambdaQueryWrapper<>();
        wrapper.gt(Video::getId,id).eq(Video::getOpen,0)
                .eq(Video::getAuditStatus, AuditStatus.SUCCESS)
                .select(Video::getId,Video::getTitle,Video::getShareNum,
                        Video::getHistoryNum,Video::getLikeNum,Video::getCollectNum,
                        Video::getCreatedTime)
                .apply("DATEDIFF(created_time, NOW()) <= 0 AND DATEDIFF(created_time, NOW()) > - {0}", days)
                .last("limit "+limit);
        return list(wrapper);
    }

    @Override
    public Collection<HotVideo> getHotRank() {
        final Set<ZSetOperations.TypedTuple<Object>> zSet = redisTemplate.opsForZSet().reverseRangeWithScores(RedisConstant.HOT_RANK, 0, -1);
        final ArrayList<HotVideo> hotVideos = new ArrayList<>();
        for (ZSetOperations.TypedTuple<Object> objectTypedTuple : zSet) {
            final HotVideo hotVideo;
            try {
                byte[] decodedBytes = Base64.getDecoder().decode(objectTypedTuple.getValue().toString());
                String jsonString = new String(decodedBytes);
                hotVideo = objectMapper.readValue(jsonString, HotVideo.class);
                hotVideo.setHot((double) objectTypedTuple.getScore().intValue());
//                hotVideo.hotFormat();
                hotVideos.add(hotVideo);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
        return hotVideos;
    }

    @Override
    public Collection<Video> getHotVideo() {
            //获取当前日期
            Calendar calendar = Calendar.getInstance();
            int date = calendar.get(Calendar.DATE);
            Map<String, Integer> map = new HashMap<>();
            map.put(RedisConstant.HOT_VIDEO + date, 10);
            map.put(RedisConstant.HOT_VIDEO + (date - 1), 3);
            map.put(RedisConstant.HOT_VIDEO + (date - 2), 2);

            //推送三天内的视频
            List<Long> hotVideos = redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
                map.forEach((k, v) -> {
                    connection.sRandMember(k.getBytes(), v);
                });
                return null;
            });
            if (ObjectUtils.isEmpty(hotVideos)) {
                return Collections.EMPTY_LIST;
            }

            ArrayList<Long> ids = new ArrayList<>();
            for (Object hotVideo : hotVideos) {
                if (!ObjectUtils.isEmpty(hotVideo)) {
                    ids.addAll((List) hotVideo);
                }
            }
            if (ObjectUtils.isEmpty(ids)) {
                return Collections.EMPTY_LIST;
            }
            System.out.println("ids:" + ids);
            HashSet hashSet = new HashSet(ids);
            Object next = hashSet.iterator().next();
            String s = next.toString();
            List<Long> list = extractNumbers(s);
            List<Video> videos = listByIds(list);
            setUserVoAndUrl(videos);
            return videos;
        }
    

    @Override
    public Collection<Video> getTypeVideo(Long typeId) {
        //根据分类推荐视频
        if(ObjectUtils.isEmpty(typeId)) {
            System.out.println("typeid不能为空");
            return Collections.EMPTY_LIST;
        }
        Type types = typeService.getById(typeId);
        if(ObjectUtils.isEmpty(types)) {
            System.out.println("分类不存在");
            return Collections.EMPTY_LIST;
        }
        Set<Long> videoIds =  interestPushService.pushByTypeId(typeId);
        System.out.println("videoIds:"+videoIds);
        List<Long> ids = new ArrayList<>(videoIds);
        List<Video> videos = listByIds(ids);

        System.out.println(videos);
        setUserVoAndUrl(videos);
        return videos;
    }

    @Override
    public void publishVideo(Video video) {
        Long userId = UserHolder.getUserId();
        //不允许修改视频
        Video oldVideo = null;
        video.setUserId(userId);
        Long videoId = video.getId();
        System.out.println("video::"+videoId);
        if(videoId!=null){
            oldVideo=getOne(new LambdaQueryWrapper<Video>().eq(Video::getId,videoId).eq(Video::getUserId,userId));
            String oldcover = oldVideo.getCover();
            Long oldurl = oldVideo.getUrl();
            String cover = video.getCover();
            Long url = video.getUrl();
            if((oldcover.equals(cover))||(oldurl.equals(url))){
                throw new CommonException("不允许更换视频，只能修改视频信息",400);
            }
            //判断分类是否存在
            Type one = typeService.getById(video.getTypeId());
            if(ObjectUtils.isEmpty(one)){
                throw new CommonException("分类不存在",400);
            }
            //判断标签数量是否超过五个
            System.out.println(video.getLabel());
            if(video.buildLabel().size()>5)
            {
                throw new CommonException("标签最多只能为五个",400);
            }
            //修改视频审核状态
            video.setAuditStatus(AuditStatus.PROCESS);
        }
            boolean isAdd = videoId == null;
            if(!isAdd){
                video.setVideoType(null);
                video.setLabel(null);
                video.setUrl(null);
                video.setCover(null);
            }else{
                if(ObjectUtils.isEmpty(video.getCover())){
                    video.setCover("Cover-Url");
                }
            }
            if(isAdd|| StringUtils.hasLength(oldVideo.getDuration())){
                String uuid = UUID.randomUUID().toString();
//                redisTemplate.opsForValue().set(uuid,true);
                LocalCache.put(uuid,true);
                try {
                    Long url = video.getUrl();
                    if (url == null || url == 0) url = oldVideo.getUrl();
                    String fileKey = "fileService...";
                    String duration = "FillUtils......";
                    video.setDuration(duration);
                }finally {
                    LocalCache.rem(uuid);
                }
            }
        long id  = idUtils.getId();
        video.setId(id);
        saveOrUpdate(video);
        //进入审核状态
        VideoTask videoTask = new VideoTask();
        videoTask.setVideo(video);
        videoTask.setOldVideo(video);
        videoTask.setIsAdd(isAdd);
        videoTask.setOldState(isAdd || video.getOpen());
        videoTask.setNewState(true);
        //调用审核模块
        //。。。。
        //如果审核通过。。
        //在系统分类视频库里放数据，添加到redis
        interestPushService.pushSystenYypeVideo(video);
        interestPushService.pushSystemVideo(video);
//        interestPushService.pushSystenStock(video);
        
    }

    @Override
    public List<Video> getByInterest() {
        Long userId = UserHolder.getUserId();
//        R r = userClient.getById(userId);
//        Object user = r.getData();
        Collection<Long> ids = new HashSet<>();
        if(!ObjectUtils.isEmpty(userId)) {
             ids = interestPushService.listVideoByUserModel(userId);
            System.out.println("你感兴趣的ids哦~~"+ids);
        }
        if(ObjectUtils.isEmpty(ids))
        {
            System.out.println("找不到你想看的咯~~~~~~~~~~~~~~~~~~~~~");
            ids=list(new LambdaQueryWrapper<Video>().orderByDesc(Video::getCreatedTime)).stream().map(Video::getId).collect(Collectors.toList());
            ids=new HashSet<>(ids).stream().limit(10).collect(Collectors.toList());
        }
        List<Video> list = listByIds(ids);
        setUserVoAndUrl(list);
        //根据分类推荐视频
        return list;
    }

    @Override
    public Long getlikeNum(Long id) {
        return baseMapper.getlikeNum(id);
    }

    @Override
    public Collection<Video> getAttentionVideo() {
        //获取用户关注的用户id
        Long userId = UserHolder.getUserId();
        
        R<List<Long>> attention = userClient.getAttention(userId);
        String data = attention.getData().toString();
        String substring = data.substring(1, data.length() - 1);
        Collection<Long> ids = new HashSet<>();
        if(substring.length()>2){
            String[] split= substring.split(",");
            for(String s : split){
                ids.add(Long.parseLong(s));
            }
        }
        else{
            ids.add(Long.parseLong(substring));
        }
        
        //根据用户id查询视频，并根据时间降序
        Collection<Video> videos = new HashSet<>();
        ids.forEach(item->{
            List<Video> list = list(new LambdaQueryWrapper<Video>().eq(Video::getUserId, item).orderByDesc(Video::getCreatedTime));
            videos.addAll(list);
        });
        return videos;
        
    }

    @Override
    public Collection<Video> getSimilarVideo(Long id) {
        Video video = getById(id);
        List<String> label = video.buildLabel();
        long limit= 1000;
        //获取视频列表
        Collection<Video> videos = new HashSet<>();
        List<Video> list ;
        //解析视频的标签
        //？？？如何获取视频，随机获取还是如何获取？先获取一千条数据然后随机找十条？如果不满十条则往下再找一千条数据，知道推荐的数据满十条
//        while(videos.size()<=10) {
            list = list(new LambdaQueryWrapper<Video>().last("limit " + limit));
            //判断视频的标签之间是否有交集
            list.forEach(item -> {
                List<String> strings = item.buildLabel();
                //判断label和strings之中有两个以上的重复的string
                if (label.stream().filter(strings::contains).count() >= 2) {
                    videos.add(item);
                }
            });
//        }
        return videos;
    }


    @Override
    public List<Video> getUserVideo(Long id) {
        
        return list(new LambdaQueryWrapper<Video>().eq(Video::getUserId,id));
    }


    public static List<Long> extractNumbers(String input) {
        List<Long> numbers = new ArrayList<>();
        Pattern pattern = Pattern.compile("\\d+");
        Matcher matcher = pattern.matcher(input);

        while (matcher.find()) {
            numbers.add(Long.parseLong(matcher.group()));
        }

        return numbers;
    }
    public void setUserVoAndUrl(Collection<Video> videos) {
        if (!ObjectUtils.isEmpty(videos)) {
            Set<Long> userIds = new HashSet<>();
//            final ArrayList<Long> fileIds = new ArrayList<>();
            for (Video video : videos) {
                userIds.add(video.getUserId());
//                fileIds.add(video.getUrl());
//                fileIds.add(video.getCover());
            }
               ArrayList<User> data = (ArrayList<User>) userClient.list(userIds).getData();
            final Map<Long, User> userMap = data.stream().collect(Collectors.toMap(User::getId, Function.identity()));
            for (Video video : videos) {
                 UserVO userVO = new UserVO();
                 User user = userMap.get(video.getUserId());
                userVO.setId(video.getUserId());
                userVO.setUserName(user.getUsername());
                userVO.setDescription(user.getDescription());
                userVO.setSex(user.getSex());
                video.setUserVo(userVO);
//                final File file = fileMap.get(video.getUrl());
//                video.setVideoType(file.getFormat());
            }
        }

    }
}
